
#ifndef SX_RECTANGLE_H
#define SX_RECTANGLE_H

namespace Sx {
namespace Graphics {

/* 
 * A primitive 2D triangle embedded in the Cartesian plane.
 * The rectangle is defined by its four sides: left, top, right, and bottom.
 * The origin of the rectangle can defined through the use of side references.
 * For a UI rectangle the references are TOP, LEFT. For a normal Cartesian
 * coordinate rectangle the references would be BOTTOM and LEFT.
 */
template <typename Real>
class Rectangle {
public:
	Rectangle();
	Rectangle(Real x, Real y, Real width, Real height);
	virtual ~Rectangle();

	enum Side { LEFT, TOP, RIGHT, BOTTOM };

	void setX(Real x);
	void setY(Real y);
	void setWidth(Real width, Side reference = LEFT);
	void setHeight(Real height, Side reference = TOP);
	void setLeft(Real left);
	void setRight(Real right);
	void setTop(Real top);
	void setBottom(Real bottom);
	void setBounds(Real left, Real top, Real right, Real bottom);
	void setSize(Real width, Real height, Side widthReference = LEFT, Side heightReference = TOP);
	void setPosition(Side side, Real position);

	Real getPosition(Side side) const;
	Real getLeft() const;
	Real getTop() const;
	Real getRight() const;
	Real getBottom() const;
	Real getX() const;
	Real getY() const;
	Real getWidth() const;
	Real getHeight() const;

	Real& left();
	Real& top();
	Real& right();
	Real& bottom();

	double getArea() const;
	double getPerimeter() const;

protected:
	Real rectLeft, rectTop, rectRight, rectBottom;
};

template <typename Real>
Rectangle<Real>::Rectangle() {
	this->rectLeft = 0;
	this->rectTop = 0;
	this->rectRight = 0;
	this->rectBottom = 0;
}

template <typename Real>
Rectangle<Real>::Rectangle(Real x, Real y, Real width, Real height) {
	this->rectLeft = x;
	this->rectTop = y;
	this->rectRight = x + width;
	this->rectBottom = y + height;
}

template <typename Real>
Rectangle<Real>::~Rectangle() {}

template <typename Real>
void Rectangle<Real>::setX(Real x) {
	this->rectLeft = x;
}

template <typename Real>
void Rectangle<Real>::setY(Real y) {
	this->rectTop = y;
}

template <typename Real>
void Rectangle<Real>::setWidth(Real width, Side reference) {
	if ( reference == LEFT ) this->rectRight = this->rectLeft + width;
	if ( reference == RIGHT ) this->rectLeft = this->rectRight - width;
}

template <typename Real>
void Rectangle<Real>::setHeight(Real height, Side reference) {
	if ( reference == TOP ) this->rectBottom = this->rectTop + height;
	if ( reference == BOTTOM ) this->rectTop = this->rectBottom - height;
}

template <typename Real>
void Rectangle<Real>::setLeft(Real left) {
	this->rectLeft = left;
}

template <typename Real>
void Rectangle<Real>::setRight(Real right) {
	this->rectRight = right;
}

template <typename Real>
void Rectangle<Real>::setTop(Real top) {
	this->rectTop = top;
}

template <typename Real>
void Rectangle<Real>::setBottom(Real bottom) {
	this->rectBottom = bottom;
}

template <typename Real>
void Rectangle<Real>::setBounds(Real left, Real top, Real right, Real bottom) {
	this->rectLeft = left;
	this->rectTop = top;
	this->rectRight = right;
	this->rectBottom = bototm;
}

template <typename Real>
void Rectangle<Real>::setSize(Real width, Real height, Side widthReference = LEFT, Side heightReference = TOP) {
	this->setWidth(width, widthReference);
	this->setHeight(height, heightReference);
}

template <typename Real>
void Rectangle<Real>::setPosition(Side side, Real position) {
	switch ( side ) {
		case LEFT: this->rectLeft = position; break;
		case TOP: this->rectTop = position; break;
		case RIGHT: this->rectRight = position; break;
		case BOTTOM: this->rectBottom = position; break;
	};
}

template <typename Real>
Real Rectangle<Real>::getPosition(Side side) const {
	switch ( side ) {
		case LEFT: return this->rectLeft;
		case TOP: return this->rectTop;
		case RIGHT: return this->rectRight;
		case BOTTOM: return this->rectBottom;
	};
}

template <typename Real>
Real Rectangle<Real>::getLeft() const {
	return this->rectLeft;
}

template <typename Real>
Real Rectangle<Real>::getTop() const {
	return this->rectTop;
}

template <typename Real>
Real Rectangle<Real>::getRight() const {
	return this->rectRight;
}

template <typename Real>
Real Rectangle<Real>::getBottom() const {
	return this->rectBottom;
}

template <typename Real>
Real Rectangle<Real>::getX() const {
	return this->rectLeft;
}

template <typename Real>
Real Rectangle<Real>::getY() const {
	return this->rectRight;
}

template <typename Real>
Real Rectangle<Real>::getWidth() const {
	return std::abs(this->rectRight - this->rectLeft);
}

template <typename Real>
Real Rectangle<Real>::getHeight() const {
	return std::abs(this->rectBottom - this->rectTop);
}

template <typename Real>
Real& Rectangle<Real>::left() {
	return this->rectLeft;
}

template <typename Real>
Real& Rectangle<Real>::top() {
	return this->rectTop;
}

template <typename Real>
Real& Rectangle<Real>::right() {
	return this->rectRight;
}

template <typename Real>
Real& Rectangle<Real>::bottom() {
	return this->rectBottom;
}

template <typename Real>
double Rectangle<Real>::getArea() const {
	return this->getHeight() * this->getWidth();
}

template <typename Real>
double Rectangle<Real>::getPerimeter() const {
	return (this->getHeight() * 2) + (this->getWidth() * 2);
}

typedef Rectangle<short> Rectangles;
typedef Rectangle<int> Rectanglei;
typedef Rectangle<unsigned int> Rectangleui;
typedef Rectangle<float> Rectanglef;
typedef Rectangle<double> Rectangled;
typedef Rectangle<long> Rectanglel;

}

}

#endif
